package gui;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import logic.Square;
import logic.Sudoku;

/**
 * 
 * @author Marco Gallardo Casu
 * 
 */
public class MyCanvas extends Canvas {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2121990717537521019L;

	private static final int N_COL = 9;
	private static final int N_ROW = 9;
	private static final int BOX = 30;
	private static final int SPACE = 2;
	private static final int MARGIN = 15;
	private static final int WIDTH = BOX * N_COL + 5 * SPACE;
	private static final int HEIGHT = BOX * N_ROW + 4 * SPACE;
	private static final int ORIGIN_0 = MARGIN + SPACE;
	private static final int ORIGIN_1 = ORIGIN_0 + BOX * 3 + 1;
	private static final int ORIGIN_2 = MARGIN + SPACE * 2 + BOX * 6;
	private static final int MARGIN_EAST = 15;
	private static final int MARGIN_NORTH = 51;
	private static final Color BLACK = new Color(0x0);
	private static final Color DARK_BLUE = new Color(0x0B0060);
	private static final Color DARK_GREEN = new Color(0x054200);
	private static final Color LIGHTING_GREEN = new Color(0x358855);
	private static final Color ORANGE = new Color(0xCC6500);
	private static final Color RED = new Color(0xFF0000);
	private static final Color WHITE = new Color(0xFFFFFF);
	private static final Color YELLOW = new Color(0xFFFF00);

	private static int square = -1;
	private static int row = -1;
	private static int col = -1;
	private static int x = -1;
	private static int y = -1;

	private Sudoku sudoku;
	private boolean[][] blocked;
	private boolean[][] bad;

	public MyCanvas() {
		super();
		blocked = null;
		addMouseListener(new MyMouseCanvasListener());
		addKeyListener(new MyKeyboardCanvasListener());
		setSudoku(new Sudoku());
		setEnabled(true);
	}

	public MyCanvas(GraphicsConfiguration arg0) {
		super(arg0);
		blocked = null;
		bad = null;
		addMouseListener(new MyMouseCanvasListener());
		addKeyListener(new MyKeyboardCanvasListener());
		sudoku = new Sudoku();
		setEnabled(true);
	}

	public MyCanvas(final String title, final Sudoku sudoku,
			final boolean[][] blocked, final boolean[][] bad) {
		super();
		this.blocked = blocked;
		this.bad = bad;
		addMouseListener(new MyMouseCanvasListener());
		addKeyListener(new MyKeyboardCanvasListener());
		setSudoku(sudoku);
		sudoku.setName(title);
		setEnabled(true);
	}

	public MyCanvas(String title, Square[] squares) {
		super();
		blocked = null;
		bad = null;
		addMouseListener(new MyMouseCanvasListener());
		addKeyListener(new MyKeyboardCanvasListener());
		sudoku = new Sudoku(title, squares);
		setEnabled(true);
	}

	public Sudoku getSudoku() {
		return sudoku;
	}

	public void setSudoku(Sudoku sudoku) {
		this.sudoku = sudoku;
	}

	@Override
	public int getHeight() {
		return (BOX * N_ROW + 2 * MARGIN + 4 * SPACE) + MARGIN_NORTH;
	}

	@Override
	public int getWidth() {
		int width = (BOX * N_COL + 2 * MARGIN + 5 * SPACE) + MARGIN_EAST;
		if (width < 200) {
			width = 200;
		}
		return width;
	}

	@Override
	public void paint(Graphics g) {
		int width = WIDTH + MARGIN;
		int height = HEIGHT + MARGIN;

		paintMargin(g, width, height);
		paintBackground(g);
		paintBorder(g, width, height);
		paintSudoku(g);
	}

	private void paintMargin(Graphics g, int width, int height) {
		g.setColor(ORANGE);
		g.fillRect(0, 0, width, MARGIN);
		g.fillRect(0, MARGIN, MARGIN, height);
		g.fillRect(MARGIN, height, width, MARGIN);
		g.fillRect(width, 0, MARGIN, height);
	}

	private void paintBackground(Graphics g) {
		g.setColor(LIGHTING_GREEN);
		g.fillRect(MARGIN, MARGIN, WIDTH, HEIGHT + 1);
	}

	private void paintBorder(Graphics g, int width, int height) {
		g.setColor(BLACK);
		g.drawRect(MARGIN, MARGIN, WIDTH - 1, HEIGHT + 1);
		g.drawRect(0, 0, width + MARGIN, height + MARGIN);
	}

	private void paintSudoku(Graphics g) {

		paintSquare(g, ORIGIN_0, ORIGIN_0, 0);
		paintSquare(g, ORIGIN_1, ORIGIN_0, 1);
		paintSquare(g, ORIGIN_2, ORIGIN_0, 2);

		paintSquare(g, ORIGIN_0, ORIGIN_1, 3);
		paintSquare(g, ORIGIN_1, ORIGIN_1, 4);
		paintSquare(g, ORIGIN_2, ORIGIN_1, 5);

		paintSquare(g, ORIGIN_0, ORIGIN_2, 6);
		paintSquare(g, ORIGIN_1, ORIGIN_2, 7);
		paintSquare(g, ORIGIN_2, ORIGIN_2, 8);

	}

	private void paintSquare(Graphics g, int x, int y, int index) {
		final int LENGTH = Square.LENGTH;
		final int width = BOX * 3 + SPACE;
		final int height = BOX * 3 + SPACE;
		Square square = sudoku.getSquare(index);

		g.setColor(WHITE);
		g.fillRect(x, y, width, SPACE);
		g.fillRect(x, y + SPACE, SPACE, height);
		g.fillRect(x + SPACE, y + height, width, SPACE);
		g.fillRect(x + width, y, SPACE, height);

		for (int row = 0; row < LENGTH; row++) {
			for (int col = 0; col < LENGTH; col++) {
				g.setColor(DARK_BLUE);
				g.fillRect(x + SPACE + BOX * col, y + SPACE + BOX * row,
						BOX - 1, BOX - 1);
				if (blocked != null && blocked[index][row * LENGTH + col]) {
					g.setColor(YELLOW);
				} else if (bad != null && bad[index][row * LENGTH + col]) {
					g.setColor(RED);
				} else {
					g.setColor(WHITE);
				}
				int value = square.getBox(row, col);
				if (value > 0 && value < 10) {
					g.drawString(String.valueOf(value), x + SPACE + BOX * col
							+ BOX / 3 + 1, y + SPACE + BOX * row + BOX / 2 + 3);
				}
			}
		}
	}

	private void paintBox(int x, int y, int index, int row, int col) {
		Graphics g = getGraphics();
		g.setColor(DARK_GREEN);
		g.fillRect(x, y, BOX - 1, BOX - 1);
		g.setColor(WHITE);
		int value = sudoku.getSquare(index).getBox(row, col);
		if (value > 0 && value < 10) {
			g.drawString(String.valueOf(value), x + BOX / 3 + 1, y + BOX / 2
					+ 3);
		}
		g.dispose();
	}

	private class MyMouseCanvasListener extends MouseAdapter {

		@Override
		public void mousePressed(MouseEvent e) {
			int x = e.getX();
			int y = e.getY();
			int originX = 0;
			int originY = 0;
			boolean found = false;
			for (int index = 0; !found && index < Sudoku.LENGTH; index++) {
				for (int row = 0; !found && row < Square.LENGTH; row++) {
					for (int col = 0; !found && col < Square.LENGTH; col++) {
						switch (index) {
						case 0:
							originX = ORIGIN_0;
							originY = ORIGIN_0;
							break;
						case 1:
							originX = ORIGIN_1;
							originY = ORIGIN_0;
							break;
						case 2:
							originX = ORIGIN_2;
							originY = ORIGIN_0;
							break;
						case 3:
							originX = ORIGIN_0;
							originY = ORIGIN_1;
							break;
						case 4:
							originX = ORIGIN_1;
							originY = ORIGIN_1;
							break;
						case 5:
							originX = ORIGIN_2;
							originY = ORIGIN_1;
							break;
						case 6:
							originX = ORIGIN_0;
							originY = ORIGIN_2;
							break;
						case 7:
							originX = ORIGIN_1;
							originY = ORIGIN_2;
							break;
						case 8:
							originX = ORIGIN_2;
							originY = ORIGIN_2;
							break;
						default:
							break;
						}
						originX += BOX * col;
						originY += BOX * row;
						int destinyX = originX + BOX;
						int destinyY = originY + BOX;
						found = originX <= x && originY <= y && destinyX >= x
								&& destinyY >= y;
						if (found) {
							MyCanvas.square = index;
							MyCanvas.row = row;
							MyCanvas.col = col;
							MyCanvas.x = originX;
							MyCanvas.y = originY;
							paint(getGraphics());
							paintBox(originX + SPACE, originY + SPACE, index,
									row, col);
						}
					}
				}
			}
		}

	}

	private class MyKeyboardCanvasListener extends KeyAdapter {

		@Override
		public void keyTyped(KeyEvent e) {
			char c = e.getKeyChar();
			if (c >= '0' && c <= '9') {
				sudoku.getSquare(square).setBox(
						Integer.parseInt(String.valueOf(c)), row, col);
				paintBox(x + SPACE, y + SPACE, square, row, col);
			}
		}

	}

}
